#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>

#include "common.h"
#include "ofprint_common.h"
#include "usb_device.h"

USB_DEV_STRUCT usb_dev_param;
int32 fd_fp256_360 = 0;



int32 usb_lib_init(ofp_dev * dev)
{
    int32 ret = libusb_init(&(dev->ctx));
    if(0 > ret)
    {
        return -1;
    }
    //pthread_mutex_init(&(dev->usb_mutex), NULL);
    //pthread_mutex_init(&(dev->hotplug_mutex), NULL);


    return 0;
}


void usb_lib_exit(ofp_dev * dev)
{
    libusb_exit(dev->ctx);
    //pthread_mutex_destroy(&(dev->usb_mutex));
    //pthread_mutex_destroy(&(dev->hotplug_mutex));

}



int32 usb_dev_ioctl(struct DEV_CMD *dev_cmd)
{
	libusb_device_handle *handle = usb_dev_param.usbdev_handle;
	int write_len = 0;
	int read_len = 0;
    int ret = 0;

	if(NULL == dev_cmd)
	{
		ERR("%s: the point dev_cmd is null, error!!!\r\n", __func__);
		return DRV_ERR;
	}

	if(NULL == handle)
	{
		ERR("%s: %s not open, error!!!\r\n", __func__, DEV_NAME);
		return DRV_ERR;
	}

	if(0 < dev_cmd->write_len)
	{
#if 0
        WD_DBG("write %d bytes to %s:\n", dev_cmd->write_len, DEV_NAME);
        int i;
		int n;
		(dev_cmd->write_len > 64)?(n = 64):(n = dev_cmd->write_len);
        for (i = 0; i < n; i++)
        {
            W_DBG("%02x ", dev_cmd->buff[i]);
			if(0 == (i + 1) % 32)
				W_DBG("\n");
        }
        W_DBG("\n");
#endif
        //pthread_mutex_lock(&(dev_ofprint->usb_mutex));
        ret = libusb_bulk_transfer(handle, 0x01, dev_cmd->buff, dev_cmd->write_len, &(write_len), dev_cmd->timeout);
        //pthread_mutex_unlock(&(dev_ofprint->usb_mutex));

		if(ret != 0)
		{
			ERR("%s:%d:%s: libusb_bulk_transfer write failed!!!\r\n", __FILE__, __LINE__, __func__);
			dev_cmd->write_len = 0;
			return DRV_ERR;
		}
		dev_cmd->write_len = write_len;
	}

    if(0 < dev_cmd->read_len)
    {
        //pthread_mutex_lock(&(dev_ofprint->usb_mutex));
        ret = libusb_bulk_transfer(handle, 0x81, dev_cmd->buff, dev_cmd->read_len, &(read_len), dev_cmd->timeout);
        //pthread_mutex_unlock(&(dev_ofprint->usb_mutex));
		if(ret !=0)
		{
			ERR("%s:%d:%s: libusb_bulk_transfer read failed!!!\r\n", __FILE__, __LINE__, __func__);
			dev_cmd->read_len = 0;
			return DRV_ERR;
		}
		dev_cmd->read_len = read_len;
#if 0
        DBG("%s: read %d bytes from %s:\r\n", __func__, dev_cmd->read_len, DEV_NAME);
        int i;
		int n;
		(dev_cmd->read_len > 64)?(n = 64):(n = dev_cmd->read_len);
        for (i = 0; i < n; i++)
        {
            DBG("%02x ", dev_cmd->buff[i]);
			if(0 == (i + 1) % 32)
				DBG("\r\n");
        }
        DBG("\n");
#endif
    }

	return DRV_OK;
}

int32 usb_check_bulk_io_ack(uint8 *buf, int32 len)
{
	if((NULL == buf) || (4 != len))
	{
		ERR("%s:%d:%s: the param is error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	//DBG("%s:%d:%s: buf %02x %02x %02x %02x\r\n", __FILE__, __LINE__, __func__, buf[0], buf[1], buf[2], buf[3]);

	if((0x55 != buf[0])&&(0x53 != buf[1])\
		&&(0x42 != buf[2])&&(0x53 != buf[3]))
	{
		//ERR("%s:%d:%s: it's not BULK_IO_ACK!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	return DRV_OK;
}

int32 usb_read_bulk_io_ack(void)
{
	uint8 buf[256] = {0x00};
	struct DEV_CMD dev_cmd;
	//uint32 msg_len = 4;

	memset((uint8 *)&dev_cmd, 0x00, sizeof(struct DEV_CMD));

    dev_cmd.buff = buf;

	dev_cmd.write_len = 0;
    dev_cmd.read_len = 4; //读数据长度,如果只想写不想读. 这里长度填0即可.
    dev_cmd.timeout = LIBUSB_BULK_TRANSFER_TIMEOUT;

	if(DRV_OK != usb_dev_ioctl(&dev_cmd))
	{
		ERR("%s:%d:%s: usb_dev_ioctl return error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	if(0 >= dev_cmd.read_len)
	{
		ERR("%s:%d:%s: not received data!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	if(DRV_OK != usb_check_bulk_io_ack(dev_cmd.buff, 4))
	{
		ERR("%s:%d:%s: not received BULK_IO_ACK!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	usb_dev_param.bulk_io_ack_state = BULK_IO_ACK_1;

	return DRV_OK;
}

int32 usb_test_handle(void)
{
	uint8 buf[256] = {0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00};
	struct DEV_CMD dev_cmd;
	uint32 msg_len = 0x80;

	memset((uint8 *)&dev_cmd, 0x00, sizeof(struct DEV_CMD));

    dev_cmd.buff = buf;
	buf[4] = BulkIoPhase_In;
	buf[5] = msg_len & 0xff;
	buf[6] = (msg_len >> 8) & 0xff;
	buf[7] = (msg_len >> 16) & 0xff;

	//DBG("%s: buf[4] = %d, buf[5] = %d\r\n", __func__, buf[4], buf[5]);

	dev_cmd.write_len = 8;
    dev_cmd.read_len = msg_len; //读数据长度,如果只想写不想读. 这里长度填0即可.
    dev_cmd.timeout = LIBUSB_BULK_TRANSFER_TIMEOUT;

	if(DRV_OK != usb_dev_ioctl(&dev_cmd))
	{
		ERR("%s:%d:%s: usb_dev_ioctl return error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	if(DRV_OK != usb_read_bulk_io_ack())
	{
		ERR("%s:%d:%s: not received BULK_IO_ACK!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	return DRV_OK;
}

int32 usb_test(void)
{
	uint16 i = 0;

	for(i = 0; i < 3; i++)
	{
		if(DRV_OK == usb_test_handle())
		{
			LOG("%s:%d:%s: usb_test_handle successfully.\r\n", __FILE__, __LINE__, __func__);
			break;
		}

		usleep(50 * 1000);
	}

	return 0;
}

int32 usb_prepare_send(int32 msg_len)
{
	uint8 buf[256] = {0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00};
	struct DEV_CMD dev_cmd;

	if(0 >= msg_len)
	{
		ERR("%s: input param msg_len = %d, error!!!\r\n", __func__, msg_len);
		return DRV_ERR;
	}

	memset((uint8 *)&dev_cmd, 0x00, sizeof(struct DEV_CMD));

	DBG("%s: msg_len = %d\r\n", __func__, msg_len);

    dev_cmd.buff = buf;
	buf[4] = BulkIoPhase_Out;
	buf[5] = msg_len & 0xff;
	buf[6] = (msg_len >> 8) & 0xff;
	buf[7] = (msg_len >> 16) & 0xff;

	//DBG("%s: buf[4] = %d, buf[5] = %d\r\n", __func__, buf[4], buf[5]);

	dev_cmd.write_len = 8;
    dev_cmd.read_len = 0; //读数据长度,如果只想写不想读. 这里长度填0即可
    dev_cmd.timeout = LIBUSB_BULK_TRANSFER_TIMEOUT;

	if(DRV_OK != usb_dev_ioctl(&dev_cmd))
	{
		ERR("%s: send failed!!!\r\n", __func__);
		return DRV_ERR;
	}

	return DRV_OK;
}


int32 usb_prepare_read(int32 msg_len)
{
	uint8 buf[256] = {0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00};
	struct DEV_CMD dev_cmd;

	if(0 >= msg_len)
	{
		ERR("%s: input param msg_len = %d, error!!!\r\n", __func__, msg_len);
		return DRV_ERR;
	}

	memset((uint8 *)&dev_cmd, 0x00, sizeof(struct DEV_CMD));

	//DBG("%s: msg_len = %d\r\n", __func__, msg_len);

	dev_cmd.buff = buf;
	buf[4] = BulkIoPhase_In;
	buf[5] = msg_len & 0xff;
	buf[6] = (msg_len >> 8) & 0xff;
	buf[7] = (msg_len >> 16) & 0xff;

	dev_cmd.write_len = 8;
	dev_cmd.read_len = 0; //读数据长度,如果只想写不想读. 这里长度填0即可.
	dev_cmd.timeout = LIBUSB_BULK_TRANSFER_TIMEOUT;

	if(DRV_OK != usb_dev_ioctl(&dev_cmd))
	{
		ERR("%s: send failed!!!\r\n", __func__);
		return DRV_ERR;
	}

	return DRV_OK;
}

int32 usb_send_data(uint8 *buf, int32 len, int32 *write_len)
{
	struct DEV_CMD dev_cmd;

	if((NULL == buf) || (0 >= len))
	{
		ERR("%s:%d:%s: the param is error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	memset((uint8 *)&dev_cmd, 0x00, sizeof(struct DEV_CMD));
	dev_cmd.buff = buf;
	dev_cmd.write_len = len;
	dev_cmd.read_len = 0;

	if(DRV_OK != usb_prepare_send(len))
	{
		ERR("%s:%d:%s: usb_prepare_send return error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	if(DRV_OK != usb_dev_ioctl(&dev_cmd))
	{
		ERR("%s:%d:%s: usb_dev_ioctl return error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	DBG("%s:%d:%s: usb_read_bulk_io_ack.\r\n", __FILE__, __LINE__, __func__);
	if(DRV_OK != usb_read_bulk_io_ack())
	{
		ERR("%s:%d:%s: not received BULK_IO_ACK!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	*write_len = dev_cmd.write_len;

	return DRV_OK;
}


int32 usb_read_data(uint8 *buf, int32 len, int32 *read_len)
{
	struct DEV_CMD dev_cmd;
	//uint16 i = 0;
	//uint16 cycle_count = len/64 + 1;
	//int32 read_byte_len = 0;

	if((NULL == buf) || (0 >= len))
	{
		ERR("%s:%d:%s: the param is error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	memset((uint8 *)&dev_cmd, 0x00, sizeof(struct DEV_CMD));


	if(DRV_OK != usb_prepare_read(len))
	{
		ERR("%s:%d:%s: usb_prepare_read return error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}


	dev_cmd.buff = buf;
	dev_cmd.write_len = 0;
	dev_cmd.read_len = len;
	dev_cmd.timeout = LIBUSB_BULK_TRANSFER_TIMEOUT;

	if(DRV_OK != usb_dev_ioctl(&dev_cmd))
	{
		ERR("%s:%d:%s: usb_dev_ioctl return error!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	if(DRV_OK != usb_read_bulk_io_ack())
	{
		ERR("%s:%d:%s: not received BULK_IO_ACK!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	*read_len = dev_cmd.read_len;

	return DRV_OK;
}


int32 usb_dev_param_init(void)
{
	memset((uint8 *)&usb_dev_param, 0x00, sizeof(USB_DEV_STRUCT));
	usb_dev_param.usbdev_handle = NULL;

	return DRV_OK;
}

int32 usb_dev_open(ofp_dev *dev)
{

	int i;
	const struct usb_id *id_table = dev->usb_info.id_table;
	libusb_device_handle *handle = NULL;
    int ret = DRV_OK;
    //pthread_mutex_lock(&(dev_ofprint->usb_mutex));

	for (i = 0; id_table[i].idVendor != 0; i++)
	{
		handle = libusb_open_device_with_vid_pid(dev_ofprint->ctx, id_table[i].idVendor, id_table[i].idProduct);
		if (NULL != handle)
		{
			break;
		}
	}

	if(NULL == handle)
	{
		WD_ERR("device open failed!!!\r\n");
		usb_dev_param.usbdev_handle = NULL;
        ret = DRV_ERR;
	}

	usb_dev_param.usbdev_handle = handle;
    //pthread_mutex_unlock(&(dev_ofprint->usb_mutex));

	return ret;
}

int32 usb_dev_close(void)
{
	if(NULL == usb_dev_param.usbdev_handle)
    {
        ERR("%s: %s not open!!!\r\n", __func__, DEV_NAME);
        return DRV_ERR;
    }
    //pthread_mutex_lock(&(dev_ofprint->usb_mutex));
	libusb_close(usb_dev_param.usbdev_handle);
    //pthread_mutex_unlock(&(dev_ofprint->usb_mutex));
	usb_dev_param.usbdev_handle = NULL;

	return DRV_OK;
}

int32 usb_dev_set_null(void)
{
	usb_dev_param.usbdev_handle = NULL;

	return DRV_OK;
}


int32 *usb_get_dev_handle(void)
{
	return (int32 *)usb_dev_param.usbdev_handle;
}

#if 0
static void print_devs(libusb_device **devs)
{
	libusb_device *dev;
	int i = 0, j = 0;
	uint8_t path[8];

	while ((dev = devs[i++]) != NULL) {
		struct libusb_device_descriptor desc;
		int r = libusb_get_device_descriptor(dev, &desc);
		if (r < 0) {
			fprintf(stderr, "failed to get device descriptor");
			return;
		}

		printf("%04x:%04x (bus %d, device %d)",
			desc.idVendor, desc.idProduct,
			libusb_get_bus_number(dev), libusb_get_device_address(dev));

		r = libusb_get_port_numbers(dev, path, sizeof(path));
		if (r > 0) {
			printf(" path: %d", path[0]);
			for (j = 1; j < r; j++)
				printf(".%d", path[j]);
		}
		printf("\n");
	}
}
#endif

int32 usb_dev_get_port_path(void)
{
	libusb_device **devs;
	ssize_t cnt;
	int ret = -1;
	char port_path[20] = {0};
	char *dev_port_path = usb_dev_param.dev_port_path;


	libusb_device *dev;
	int i = 0, j = 0;
	uint8_t path[8];


	memset(dev_port_path, 0x00, DEV_PORT_PATH_LEN);
	usb_dev_param.dev_port_path_valid_flag = 0;
    //pthread_mutex_lock(&(dev_ofprint->usb_mutex));

	cnt = libusb_get_device_list(dev_ofprint->ctx, &devs);
	if (cnt < 0){
		goto USB_DEV_GET_PORT_PATH_FAILED;
	}


	while ((dev = devs[i++]) != NULL) {
		struct libusb_device_descriptor desc;
		int r = libusb_get_device_descriptor(dev, &desc);
		if (r < 0) {
			fprintf(stderr, "failed to get device descriptor");
			goto USB_DEV_GET_PORT_PATH_FREE;
		}

		if((0x33a7 == desc.idVendor)&&(0x2388 == desc.idProduct))
		{
			D_DBG("%04x:%04x (bus %d, device %d)",
				desc.idVendor, desc.idProduct,
				libusb_get_bus_number(dev), libusb_get_device_address(dev));

			r = libusb_get_port_numbers(dev, path, sizeof(path));
			if (r > 0) {
				DBG(" path: %d", path[0]);
				snprintf(port_path, 20, "%d", path[0]);
				for (j = 1; j < r; j++)
				{
					DBG(".%d", path[j]);
					snprintf(port_path+strlen(port_path), 20-strlen(port_path), ".%d", path[j]);
				}
			}
			DBG("\n");

			snprintf(dev_port_path, DEV_PORT_PATH_LEN, "/sys/bus/usb/devices/%d-%s", libusb_get_bus_number(dev), port_path);
			WD_DBG("usb dev port path: %s\n", dev_port_path);
			usb_dev_param.dev_port_path_valid_flag = 1;
			ret = 0;
		}
	}

USB_DEV_GET_PORT_PATH_FREE:
	libusb_free_device_list(devs, 1);


USB_DEV_GET_PORT_PATH_FAILED:
	//pthread_mutex_unlock(&(dev_ofprint->usb_mutex));
	return ret;
}

int usb_dev_set_port_path_valid_flag(uint8 flag)
{
	usb_dev_param.dev_port_path_valid_flag = flag;
	return 0;
}

uint8 usb_dev_get_port_path_valid_flag(void)
{
	return usb_dev_param.dev_port_path_valid_flag;
}

int usb_dev_enable_autosuspend(void)
{
	char set_control_cmd[500] = {0};

	if(1 != usb_dev_param.dev_port_path_valid_flag)
	{
		D_DBG("not get dev_port_path!\r\n");
		return -1;
	}

#if 1//暂不启用自动挂起，by hcq, 20231031
	if(1 == usb_dev_param.autosuspend_flag)
	{
		snprintf(set_control_cmd, 500, "echo \"auto\" > %s%s", usb_dev_param.dev_port_path, "/power/control");
		WD_LOG("%s\n", set_control_cmd);
		system(set_control_cmd);

		memset(set_control_cmd, 0x00, 500);
		snprintf(set_control_cmd, 500, "echo 2 > %s%s", usb_dev_param.dev_port_path, "/power/autosuspend");
		WD_LOG("%s\n", set_control_cmd);
		system(set_control_cmd);

		memset(set_control_cmd, 0x00, 500);
		snprintf(set_control_cmd, 500, "echo 2000 > %s%s", usb_dev_param.dev_port_path, "/power/autosuspend_delay_ms");
		WD_LOG("%s\n", set_control_cmd);
		system(set_control_cmd);
	}
#endif

	return 0;
}

int usb_dev_disable_autosuspend(void)
{
	char set_control_cmd[500] = {0};

	if(1 != usb_dev_param.dev_port_path_valid_flag)
	{
		D_DBG("not get dev_port_path!\r\n");
		return -1;
	}

	snprintf(set_control_cmd, 500, "echo \"on\" > %s%s", usb_dev_param.dev_port_path, "/power/control");
	WD_DBG("%s\n", set_control_cmd);
	system(set_control_cmd);
	return 0;
}


#if 0
int print_devs_test(void)
{
	libusb_device **devs;
	int r;
	ssize_t cnt;
#if 0
	r = libusb_init(NULL);
	if (r < 0)
		return r;
#endif
	cnt = libusb_get_device_list(NULL, &devs);
	if (cnt < 0){
		libusb_exit(NULL);
		return (int) cnt;
	}

	print_devs(devs);
	libusb_free_device_list(devs, 1);

	libusb_exit(NULL);
	return 0;
}
#elif 0
int print_devs_test(void)
{
	char port_path[100] = {0};

	if(0 == usb_dev_get_port_path(port_path, 100))
	{
		D_LOG("port_path = %s\r\n", port_path);
	}

	return 0;
}
#endif

int32 usb_set_autosuspend_flag(uint8 flag)
{
	usb_dev_param.autosuspend_flag = flag;
	return 0;
}

int32 usb_dev_module_init(void)
{
#if 0
	if(DRV_OK != usb_dev_open())
	{
		ERR("%s:%d:%s: usb_dev_open failed!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}
#endif

	if(DRV_OK != usb_dev_param_init())
	{
		ERR("%s:%d:%s: usb_dev_param_init failed!!!\r\n", __FILE__, __LINE__, __func__);
		return DRV_ERR;
	}

	return DRV_OK;
}


